﻿using System;
using System.Collections;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Linq;

using MapCenterSystem.DataInfo;
using MapCenterSytem.Process;
using MapCenterSystem.ServiceProvider.LocalMap;
using MapCenterSystem.ServiceProvider.GoogleMap;
using MapCenterSystem.Utility;
using System.Drawing;
using System.Drawing.Imaging;
using MapCenterSystem.DefineType;
using System.Web.SessionState;
using System.Collections.Generic;
using System.IO;
using System.Globalization;

namespace MobiMap.Guest
{
    /// <summary>
    /// Summary description for $codebehindclassname$
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class MapHandler : IHttpHandler, IRequiresSessionState
    {
        #region Cac thuoc tinh
        static int TILE_SIZE = 256;
        static int MAX_WIDTH = TILE_SIZE * 2;
        static int MAX_HEIGHT = TILE_SIZE * 2;
        static int DEFAULT_WIDTH = 240;
        static int DEFAULT_HEIGHT = 320;
        static int DEFAULT_ZOOM = 15;
        static int DEFAULT_TYPE = 0;
        static int MAX_ZOOM = 17;
        static int MIN_ZOOM = 14;
        static double DEFAULT_LONG = 106.682374;
        static double DEFAULT_LAT = 10.762737;

        int screenWidth = DEFAULT_WIDTH;
        int screenHeight = DEFAULT_HEIGHT;

        Point placeCoor;

        // ???
        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
        #endregion

        public void ProcessRequest(HttpContext context)
        {
            #region Xu ly tong quan tren ban do
            HttpResponse response = context.Response;
            HttpRequest request = context.Request;
            response.ContentType = "image/png";

            MapInfoEx map = null;
            #region Kich thuoc map
            if (request.QueryString["screenWidth"] != null)
                screenWidth = int.Parse(request.QueryString["screenWidth"]);
            if (request.QueryString["screenHeight"] != null)
                screenHeight = int.Parse(request.QueryString["screenHeight"]);
            if (screenWidth > MAX_WIDTH)
                screenWidth = MAX_WIDTH;
            if (screenHeight > MAX_HEIGHT)
                screenHeight = MAX_HEIGHT;
            #endregion

            #region Di chuyen ban do
            if (context.Session["MAP"] != null)
            {
                map = (MapInfoEx)context.Session["MAP"];
                //map type
                if (request.QueryString["type"] != null)
                    map.MapType = int.Parse(request.QueryString["type"]);

                //map zoom
                if (request.QueryString["zoom"] != null)
                {
                    int z = int.Parse(request.QueryString["zoom"]);
                    if ((map.Zoom == MAX_ZOOM && z == 1) || (map.Zoom == MIN_ZOOM && z == -1))
                    {
                        // strBuilder = string.Format("<script language=javascript>alert('" + "Over Zoom !" + "');</script>", "Message");
                        //response.Write(strBuilder);
                    }
                    else
                    {
                        map.Zoom += z;
                    }
                }

                if ((request.QueryString["move"] != null))
                {
                    string move = request.QueryString["move"];
                    double distance = 0.00008 * Math.Pow(2, 20 - map.Zoom);
                    if (move == "right")
                    {
                        map.CoordinateCenter.Longitude += distance;

                    }
                    else if (move == "left")
                    {
                        map.CoordinateCenter.Longitude -= distance;
                    }
                    else if (move == "up")
                    {
                        map.CoordinateCenter.Latitude += distance;
                    }
                    else if (move == "bottom")
                    {
                        map.CoordinateCenter.Latitude -= distance;
                    }


                }
                //sửa lại chỗ này để canh đều tạo ra chỉnh vẽ vòng tròn ra chính giữa
                //cái này nó tạo ảnh trước
                //sửa chỗ này
                if (context.Session["mobimap_mylocation"] != null && (request.QueryString["move"] == null))
                {
                    //thêm chỗ này nha
                    string[] strMyLocation = (string[])context.Session["mobimap_mylocation"];
                    double longitude;
                    double latitude;
                    longitude = double.Parse(strMyLocation[2], CultureInfo.InvariantCulture);
                    latitude = double.Parse(strMyLocation[3], CultureInfo.InvariantCulture);
                    map.CoordinateCenter = new Coordinate(latitude, longitude);
                }
                //kết thúc sửa
                if (screenWidth != DEFAULT_WIDTH || screenHeight != DEFAULT_HEIGHT)
                    map.Size = new Size(screenWidth, screenHeight);
            }
            else
            {
                map = new MapInfoEx();
                map.Zoom = DEFAULT_ZOOM;
                map.Size = new Size(screenWidth, screenHeight);
                map.MapType = DEFAULT_TYPE;
                map.CoordinateCenter = new Coordinate(DEFAULT_LAT, DEFAULT_LONG);
            }
            #endregion

            #region Ban do o trang thai Trang chu
            Point addrPoint = Point.Empty;
            string[] homeInfo = { };
            if (context.Session["mobimap_homeinfo"] != null)
            {
                homeInfo = (string[])context.Session["mobimap_homeinfo"];
                double longitude;
                double latitude;
                longitude = double.Parse(homeInfo[2], CultureInfo.InvariantCulture);
                latitude = double.Parse(homeInfo[3], CultureInfo.InvariantCulture);

                if ((request.QueryString["move"] == null
                    && request.QueryString["zoom"] == null
                    && request.QueryString["type"] == null)
                    || request.QueryString["showinfo"] != null)
                {
                    map.CoordinateCenter = new Coordinate(latitude, longitude);
                }

                addrPoint = LocateConvert.ToPoint(new Coordinate(latitude, longitude), map.Zoom);
            }
            #endregion

            #region Ban do o trang thai Tim duong di
            List<GraphNodeInfoEx> lstGraphNode = new List<GraphNodeInfoEx>();
            List<Point> lstPoint = new List<Point>();
            List<PlaceInfo> lstService = new List<PlaceInfo>(); // list cac service
            List<Point> lstServicePoint = new List<Point>();

            if (context.Session["mobimap_lstGraphNode"] != null)
            {
                lstGraphNode = (List<GraphNodeInfoEx>)context.Session["mobimap_lstGraphNode"];
                if ((request.QueryString["move"] == null
                    && request.QueryString["zoom"] == null
                    && request.QueryString["type"] == null)
                    || request.QueryString["showinfo"] != null)
                {
                    map.CoordinateCenter = new Coordinate(lstGraphNode[0].Location.Latitude,
                                                    lstGraphNode[0].Location.Longitude);
                    if (request.QueryString["idxFlag"] == "2")
                    {
                        int lastIndex = lstGraphNode.Count - 1;
                        map.CoordinateCenter = new Coordinate(lstGraphNode[lastIndex].Location.Latitude,
                                                    lstGraphNode[lastIndex].Location.Longitude);
                    }
                }
            }
            #endregion

            if (context.Application["mobimap_mapsource"] != null)
            {
                map.MapSource = (int)context.Application["mobimap_mapsource"];
            }

            // Sử dụng lớp GoogleMapProviderEx để load ảnh chứ không dùng dịch vụ của Google
            map.MapSource = 0;

            map.GlobalToMap();
            map.Tile = new Point(map.MapCenter.X / TILE_SIZE, map.MapCenter.Y / TILE_SIZE);
            map.MapStore = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "MapData");
            context.Session["MAP"] = map;
            System.Drawing.Image result;
            #endregion

            #region Xy ly chi tiet cac trang thai tren ban do
            #region Try
            try
            {
                #region Lay source map tu local hay googlemap
                if (map.MapSource == 0)
                {
                    GoogleMapProviderEx g = new GoogleMapProviderEx();
                    // Khi thiếu ảnh, sẽ bị văng khỏi try và vào catch -> Load bản đồ mặc định
                    result = g.GetMapImage(map);
                }
                else
                {
                    LocalMapProviderEx g = new LocalMapProviderEx();
                    result = g.GetMapImage(map);
                }
                #endregion

                #region Tim dia diem
                string strRespond = string.Empty;
                bool rsDraw;
                if (context.Session["mobimap_homeinfo"] != null)
                {
                    strRespond = "address";
                    int flagX = addrPoint.X - (map.MapCenter.X - result.Width / 2);
                    int flagY = addrPoint.Y - (map.MapCenter.Y - result.Height / 2);

                    // Ve ban kinh
                    string[] lstStr = (string[])context.Session["mobimap_homeinfo"];
                    //Luân Định sửa chỗ này 
                    rsDraw = DrawFlag(result, @"Image/inputAddress32.png", flagX, flagY);
                    if (rsDraw == false)
                    {
                        strRespond += "@" + -1;
                        strRespond += "@" + -1;
                    }
                    else
                    {
                        strRespond += FlagPosToString(flagX, flagY, 32, 32, result.Width, result.Height);

                        if (request.QueryString["showinfo"] != null)
                        {
                            strRespond += "@" + homeInfo[0] + "@" + homeInfo[1];
                            if (homeInfo.Length == 5)
                                strRespond += "@" + homeInfo[4];
                        }
                    }
                }
                #endregion

                #region Vi tri cua toi
                if (context.Session["mobimap_mylocation"] != null)
                {
                    homeInfo = (string[])context.Session["mobimap_mylocation"];
                    double longitude;
                    double latitude;
                    longitude = double.Parse(homeInfo[2], CultureInfo.InvariantCulture);
                    latitude = double.Parse(homeInfo[3], CultureInfo.InvariantCulture);

                    if ((request.QueryString["move"] == null
                        && request.QueryString["zoom"] == null
                        && request.QueryString["type"] == null)
                        || request.QueryString["showinfo"] != null)
                    {
                        map.CoordinateCenter = new Coordinate(latitude, longitude);
                    }

                    addrPoint = LocateConvert.ToPoint(new Coordinate(latitude, longitude), map.Zoom);
                    strRespond = "myLocation";
                    int flagX = addrPoint.X - (map.MapCenter.X - result.Width / 2);
                    int flagY = addrPoint.Y - (map.MapCenter.Y - result.Height / 2);

                    DrawEllipse(result, latitude, longitude, map);

                    rsDraw = DrawFlag(result, @"Image/myLocation32.png", flagX, flagY);
                    if (rsDraw == false)
                    {
                        strRespond += "@" + -1;
                        strRespond += "@" + -1;
                    }
                    else
                    {
                        strRespond += FlagPosToString(flagX, flagY, 32, 32, result.Width, result.Height);

                        if (request.QueryString["showinfo"] != null)
                        {
                            strRespond += "@" + homeInfo[0] + "@" + homeInfo[1];
                            if (homeInfo.Length == 5)
                                strRespond += "@" + homeInfo[4];
                        }
                    }
                }
                #endregion

                #region Tim kiem xung quanh
                if (context.Session["mobimap_lstService"] != null)
                {
                    // ve cac dich vu len man hinh
                    lstService = (List<PlaceInfo>)context.Session["mobimap_lstService"];
                    lstServicePoint = ToListScreenPoint(lstService, map.MapCenter, result.Width, result.Height, map.Zoom);
                    if (context.Session["mobimap_mylocation"] != null)
                        strRespond += "@lstService";
                    else
                        strRespond = "lstService";

                    for (int i = 0; i < lstServicePoint.Count; i++)
                    {
                        rsDraw = DrawFlag(result, @"Image/inputAddress32.png", lstServicePoint[i].X, lstServicePoint[i].Y);
                        if (rsDraw == false)
                        {
                            strRespond += "@" + -1;
                            strRespond += "@" + -1;
                        }
                        else
                        {

                            strRespond += FlagPosToString(lstServicePoint[i].X, lstServicePoint[i].Y, 32, 32, result.Width, result.Height);

                            if (request.QueryString["showinfo"] != null)
                            {
                                strRespond += "@" + lstService[i].Location.Longitude.ToString() + "@" + lstService[i].Location.Latitude.ToString();
                                if (homeInfo.Length == 5)
                                    strRespond += "@" + homeInfo[4];
                            }

                        }
                    }
                }
                #endregion

                #region Tim kiem duong di
                if (context.Session["mobimap_lstGraphNode"] != null)
                {
                    //Ve duong di giua 2 diem   
                    lstPoint = ToListScreenPoint(lstGraphNode, map.MapCenter, result.Width, result.Height, map.Zoom);
                    result = DrawDirection(result, map.MapCenter, lstPoint);

                    strRespond = "street";
                    int startX = lstPoint[0].X;
                    int startY = lstPoint[0].Y;
                    rsDraw = DrawFlag(result, @"Image/startAddress32.png", startX, startY);
                    if (rsDraw == false)
                    {
                        strRespond += "@" + -1;
                        strRespond += "@" + -1;
                    }
                    else
                    {
                        strRespond += FlagPosToString(startX, startY, 32, 32, result.Width, result.Height);
                    }


                    int endX = lstPoint[lstPoint.Count - 1].X;
                    int endY = lstPoint[lstPoint.Count - 1].Y;
                    rsDraw = DrawFlag(result, @"Image/endAddress32.png", endX, endY);
                    if (rsDraw == false)
                    {
                        strRespond += "@" + -1;
                        strRespond += "@" + -1;
                    }
                    else
                    {
                        strRespond += FlagPosToString(endX, endY, 32, 32, result.Width, result.Height);
                    }


                    if (request.QueryString["showinfo"] != null)
                    {
                        if (request.QueryString["idxFlag"] == "1")
                        {
                            homeInfo = (string[])context.Session["mobimap_startinfo"];
                            strRespond += "@" + "start" + "@" + homeInfo[0] + "@" + homeInfo[1];
                        }
                        else //idxFlag = 2
                        {
                            homeInfo = (string[])context.Session["mobimap_endinfo"];
                            strRespond += "@" + "end" + "@" + homeInfo[0] + "@" + homeInfo[1];
                        }

                        if (homeInfo.Length == 5)
                            strRespond += "@" + homeInfo[4];
                    }
                }
                #endregion

                context.Session["mobimap_placeinfo"] = strRespond;

                result.Save(context.Response.OutputStream, ImageFormat.Png);
                result.Dispose();
            }
            #endregion

            #region Catch
            catch (Exception ex)
            {
                //map = new MapInfoEx();
                map.Zoom = DEFAULT_ZOOM;
                //map.Size = new Size(screenWidth, screenHeight);
                map.MapType = DEFAULT_TYPE;
                map.CoordinateCenter = new Coordinate(DEFAULT_LAT, DEFAULT_LONG);

                map.GlobalToMap();
                map.Tile = new Point(map.MapCenter.X / TILE_SIZE, map.MapCenter.Y / TILE_SIZE);
                map.MapStore = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "MapData");
                context.Session["MAP"] = map;
                if (map.MapSource == 0)
                {
                    GoogleMapProviderEx g = new GoogleMapProviderEx();
                    result = g.GetMapImage(map);
                }
                else
                {
                    LocalMapProviderEx g = new LocalMapProviderEx();
                    result = g.GetMapImage(map);
                }
                result.Save(context.Response.OutputStream, ImageFormat.Png);
                result.Dispose();
            }
            #endregion
            #endregion
        }

        #region Cac ham Ve do hoa va Ho tro
        //Chuyen sang toa do tren man hinh
        public List<Point> ToListScreenPoint(List<GraphNodeInfoEx> lst, Point mapCenter, int scrWidth, int scrHeight, int mapZoom)
        {
            int left = mapCenter.X - scrWidth / 2;
            int top = mapCenter.Y - scrHeight / 2;

            List<Point> lstPoint = new List<Point>();
            Point p;
            for (int i = 0; i < lst.Count; i++)
            {
                p = LocateConvert.ToPoint(lst[i].Location, mapZoom);
                lstPoint.Add(new Point(p.X - left, p.Y - top));
            }
            return lstPoint;
        }

        //Chuyen sang toa do tren man hinh
        public List<Point> ToListScreenPoint(List<PlaceInfo> lst, Point mapCenter, int scrWidth, int scrHeight, int mapZoom)
        {
            int left = mapCenter.X - scrWidth / 2;
            int top = mapCenter.Y - scrHeight / 2;

            List<Point> lstPoint = new List<Point>();
            Point p;
            for (int i = 0; i < lst.Count; i++)
            {
                p = LocateConvert.ToPoint(lst[i].Location, mapZoom);
                lstPoint.Add(new Point(p.X - left, p.Y - top));
            }
            return lstPoint;
        }

        //Ve duong di giua 2 diem tren ban do
        public System.Drawing.Image DrawDirection(System.Drawing.Image image, Point center, List<Point> lstPoint)
        {
            //System.Drawing.Image imgResult = image;

            Graphics g = Graphics.FromImage(image);
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            Pen pen = new Pen(Color.Blue, 3);
            Font drawFont = new Font("Arial", 12);
            SolidBrush drawBrush = new SolidBrush(Color.Black);


            Point startNode = lstPoint[0];
            Point endNode = lstPoint[lstPoint.Count - 1];

            for (int i = 0; i < lstPoint.Count - 1; i++)
            {
                g.DrawLine(pen, lstPoint[i], lstPoint[i + 1]);
            }

            return image;
        }

        // Ve ban kinh quanh Vi tri cua toi
        public void DrawEllipse(Image image, double latitude, double longitude, MapInfoEx map)
        {
            Point addrPoint = LocateConvert.ToPoint(new Coordinate(latitude, longitude), map.Zoom);
            int flagX = addrPoint.X - (map.MapCenter.X);
            int flagY = addrPoint.Y - (map.MapCenter.Y);
            Graphics g = Graphics.FromImage(image);
            Size size = new Size(image.Width, image.Height);
            Image ellipse = Image.FromFile(AppDomain.CurrentDomain.BaseDirectory + @"Image/Ellipse.png");
            g.DrawImage(ellipse, flagX, flagY, size.Width, size.Height);
        }

        // Ve dia diem
        public bool DrawFlag(Image imageMap, string imgFlagPath, int x, int y)
        {

            Image flag = Image.FromFile(AppDomain.CurrentDomain.BaseDirectory + imgFlagPath);
            int left = x - flag.Width / 2;
            int top = y - flag.Height;

            if (left < -flag.Width || left > imageMap.Width || top < -flag.Height || top > imageMap.Height)
                return false;

            Graphics g = Graphics.FromImage(imageMap);
            g.DrawImage(flag, left, top, 32, 32);

            return true;
        }

        // Chuyen Toa do dia diem sang Chuoi co dinh dang
        public string FlagPosToString(int x, int y, int width, int height, int mapwidth, int mapheight)
        {
            int left = x - width / 2;
            int top = y - height;
            if (left < 0)
            {
                width = width + left;
                left = 0;
            }
            if (top < 0)
            {
                height = height + top;
                top = 0;
            }
            if (mapwidth - left < width)
                width = mapwidth - left;
            if (mapheight - top < height)
                height = mapheight - top;

            return "@" + left + ";" + top + "@" + width + ";" + height;
        }
        #endregion
    }
}
